package manager

import (
	"context"
	"fmt"
	"gitee.com/xfrm/middleware/internal/dbrouter"
	"gitee.com/xfrm/middleware/xconfig"
	"gitee.com/xfrm/middleware/xsql"
)

// Manager 管理数据库实例和连接池
type Manager struct {
	center     xconfig.ConfigCenter
	clusterMgr *dbrouter.InstanceManager
	// 动态配置
	sqlconfs  map[string]*xsql.MysqlConf
	namespace string
}

//NewManager 实例化DB路由对象
func NewManager(center xconfig.ConfigCenter, namespace string) (*Manager, error) {
	mgr := &Manager{
		center: center,
	}
	if namespace == "" {
		namespace = xconfig.DefaultMysqlNamespace
	}
	mgr.namespace = namespace
	var confs = make(map[string]*xsql.MysqlConf)
	err := center.UnmarshalWithNamespace(context.Background(), namespace, &confs)
	if err != nil {
		return nil, err
	}
	mgr.sqlconfs = confs
	factory := func(make map[string]*xsql.MysqlConf) func(ctx context.Context, cluster string) (in dbrouter.Instancer, err error) {
		return func(ctx context.Context, cluster string) (in dbrouter.Instancer, err error) {
			if sqlcfg, ok := confs[cluster]; ok {
				return factory(ctx, cluster, sqlcfg)
			}
			return nil, err
		}
	}(confs)
	mgr.clusterMgr = dbrouter.NewInstanceManager(factory)
	mgr.observer(context.Background())
	return mgr, nil
}

// GetDB return manager.DB without transaction
func (m *Manager) GetDB(ctx context.Context, cluster string) (*DB, error) {
	instance, err := m.getInstance(ctx, cluster)
	if err != nil {
		return nil, err
	}
	db := new(DB)
	db.cluster = cluster
	db.db = instance.db
	return db, nil
}

// IgnoreTableNameCheck ignore check table name rule
func (m *Manager) IgnoreTableNameCheck() {
	bCheckTableName = false
}

//获取DB实例
func (m *Manager) getInstance(ctx context.Context, instance string) (dbInstance *DBInstance, err error) {
	in := m.clusterMgr.Get(ctx, instance)
	if in == nil {
		err = fmt.Errorf("db instance not find: instance:%s", instance)
		return nil, err
	}

	dbInstance, ok := in.(*DBInstance)
	if !ok {
		err = fmt.Errorf("db instance type error: instance:%s ", instance)

		return nil, err
	}

	return dbInstance, err
}

func (m *Manager) observer(ctx context.Context) error {
	m.center.RegisterObserver(ctx, xconfig.NewConfigObserver(func(ctx context.Context, event *xconfig.ChangeEvent) {
		if event.Namespace != m.namespace {
			return
		}
		//全部监听到，全部关闭
		m.clusterMgr.Close()
	}))
	return nil
}
